home *** CD-ROM | disk | FTP | other *** search
- From: decvax!minow (Martin Minow)
- Subject: MicroEmacs (Part 1 of 6)
- Newsgroups: mod.sources
- Approved: jpn@panda.UUCP
-
- Mod.sources: Volume 4, Issue 68
- Submitted by: decvax!minow (Martin Minow)
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create the files:
- # Readme.txt
- # basic.c
- # buffer.c
- # cinfo.c
- # def.h
- # display.c
- # This archive created: Sun Apr 13 11:15:10 1986
- export PATH; PATH=/bin:$PATH
- echo shar: extracting "'Readme.txt'" '(4164 characters)'
- if test -f 'Readme.txt'
- then
- echo shar: will not over-write existing file "'Readme.txt'"
- else
- cat << \SHAR_EOF > 'Readme.txt'
- This is the only official distribution of MicroEmacs. Accept no
- substitutes. It is distributed on Usenet on 6 shar archives.
- Save them as uemacs1.shar ... uemacs6.shar.
-
- Move to .../uemacs and unshar all six source files:
- uemacs[1-3].shar Editor Mainline
- uemacs4.shar System-specific sources
- uemacs5.shar Terminal-specific sources
- uemacs6.shar Out of date TeX documentation
-
- The shar files will automatically create the following directory structure:
-
- .../uemacs Editor mainline sources
- .../uemacs/sys System specific sources
- .../uemacs/sys/atari Atari ST
- .../uemacs/sys/cpm86
- .../uemacs/sys/msdos
- .../uemacs/sys/ultrix (and other 4.2 bsd Unix systems)
- .../uemacs/sys/vms
- .../uemacs/tty Terminal handler sources
- .../uemacs/tty/ansi VT100 and other Ansi-style terminals.
- .../uemacs/tty/atari
- .../uemacs/tty/heath
-
- To compile, choose one system, and one tty, and copy the files from the
- appropriate subdirectory into the mainline directory. Then compile all
- sources, and link. The ultrix version includes a Makefile.
-
- Unfortunately, the documentation is not yet ready. You will have
- to dig the keypad bindings out of the source code. Most are setup
- in symbol.c, a few might be set in the terminal or system specific
- modules.
-
- You can get a current keypad binding chart by entering the command
-
- <META>X display-bindings
-
- <META> is usually bound to <ESC> or <ALT>. Here are my possibly
- out-of-date bindings. Note the following abbreviations:
-
- C-<something> Control-<something>
- M-<something> Meta -- generally the <ESC> key.
- F10 (etc. -- a keypad function key).
-
- Up back-line
- Down forw-line
- Left back-char
- Right forw-char
- Find search-again
- Insert yank
- Remove kill-region
- Select set-mark
- Previous back-page
- Next forw-page
- Help help
- Do execute-macro
- F17 back-window
- F18 forw-window
- F19 enlarge-window
- F20 shrink-window
- Rubout back-del-char
- C-@ set-mark
- C-A goto-bol
- C-B back-char
- C-C spawn-cli
- C-D forw-del-char
- C-E goto-eol
- C-F forw-char
- C-G abort
- Backspace back-del-char
- C-J ins-nl-and-indent
- C-K kill-line
- C-L refresh
- Return ins-nl
- C-N forw-line
- C-O ins-nl-and-backup
- C-P back-line
- C-Q quote
- C-R back-i-search
- C-S forw-i-search
- C-T twiddle
- C-V forw-page
- C-W kill-region
- C-Y yank
- C-Z jeff-exit
- M-! reposition-window
- M-% query-replace
- M-. set-mark
- M-< goto-bob
- M-> goto-eob
- M-B back-word
- M-C cap-word
- M-D forw-del-word
- M-F forw-word
- M-L lower-word
- M-Q quote
- M-R back-search
- M-S forw-search
- M-U upper-word
- M-V back-page
- M-W copy-region
- M-X extended-command
- M-Rubout back-del-word
- C-M-G abort
- M-Backspace back-del-word
- C-M-R display-message
- C-M-V display-version
- C-X ( start-macro
- C-X ) end-macro
- C-X 1 only-window
- C-X 2 split-window
- C-X = display-position
- C-X B use-buffer
- C-X E execute-macro
- C-X G goto-line
- C-X K kill-buffer
- C-X N forw-window
- C-X P back-window
- C-X R back-i-search
- C-X S forw-i-search
- C-X Z enlarge-window
- C-X C-B display-buffers
- C-X C-C quit
- C-X C-D display-directory
- C-X C-F set-file-name
- C-X C-G abort
- C-X C-L lower-region
- C-X C-N down-window
- C-X C-O del-blank-lines
- C-X C-P up-window
- C-X C-R file-read
- C-X C-S file-save
- C-X C-U upper-region
- C-X C-V file-visit
- C-X C-W file-write
- C-X C-X swap-dot-and-mark
- C-X C-Z shrink-window
-
- SHAR_EOF
- if test 4164 -ne "`wc -c < 'Readme.txt'`"
- then
- echo shar: error transmitting "'Readme.txt'" '(should have been 4164 characters)'
- fi
- fi
- echo shar: extracting "'basic.c'" '(7726 characters)'
- if test -f 'basic.c'
- then
- echo shar: will not over-write existing file "'basic.c'"
- else
- cat << \SHAR_EOF > 'basic.c'
- /*
- * Name: MicroEMACS
- * Basic cursor motion commands.
- * Version: 29
- * Last edit: 05-Feb-86
- * By: rex::conroy
- * decvax!decwrl!dec-rhea!dec-rex!conroy
- *
- * The routines in this file are the basic
- * command functions for moving the cursor around on
- * the screen, setting mark, and swapping dot with
- * mark. Only moves between lines, which might make the
- * current buffer framing bad, are hard.
- */
- #include "def.h"
-
- /*
- * Go to beginning of line.
- */
- gotobol(f, n, k)
- {
- curwp->w_doto = 0;
- return (TRUE);
- }
-
- /*
- * Move cursor backwards. Do the
- * right thing if the count is less than
- * 0. Error if you try to move back from
- * the beginning of the buffer.
- */
- backchar(f, n, k)
- register int n;
- {
- register LINE *lp;
-
- if (n < 0)
- return (forwchar(f, -n, KRANDOM));
- while (n--) {
- if (curwp->w_doto == 0) {
- if ((lp=lback(curwp->w_dotp)) == curbp->b_linep)
- return (FALSE);
- curwp->w_dotp = lp;
- curwp->w_doto = llength(lp);
- curwp->w_flag |= WFMOVE;
- } else
- curwp->w_doto--;
- }
- return (TRUE);
- }
-
- /*
- * Go to end of line.
- */
- gotoeol(f, n, k)
- {
- curwp->w_doto = llength(curwp->w_dotp);
- return (TRUE);
- }
-
- /*
- * Move cursor forwards. Do the
- * right thing if the count is less than
- * 0. Error if you try to move forward
- * from the end of the buffer.
- */
- forwchar(f, n, k)
- register int n;
- {
- if (n < 0)
- return (backchar(f, -n, KRANDOM));
- while (n--) {
- if (curwp->w_doto == llength(curwp->w_dotp)) {
- if (curwp->w_dotp == curbp->b_linep)
- return (FALSE);
- curwp->w_dotp = lforw(curwp->w_dotp);
- curwp->w_doto = 0;
- curwp->w_flag |= WFMOVE;
- } else
- curwp->w_doto++;
- }
- return (TRUE);
- }
-
- /*
- * Go to the beginning of the
- * buffer. Setting WFHARD is conservative,
- * but almost always the case.
- */
- gotobob(f, n, k)
- {
- curwp->w_dotp = lforw(curbp->b_linep);
- curwp->w_doto = 0;
- curwp->w_flag |= WFHARD;
- return (TRUE);
- }
-
- /*
- * Go to the end of the buffer.
- * Setting WFHARD is conservative, but
- * almost always the case.
- */
- gotoeob(f, n, k)
- {
- curwp->w_dotp = curbp->b_linep;
- curwp->w_doto = 0;
- curwp->w_flag |= WFHARD;
- return (TRUE);
- }
-
- /*
- * Move forward by full lines.
- * If the number of lines to move is less
- * than zero, call the backward line function to
- * actually do it. The last command controls how
- * the goal column is set.
- */
- forwline(f, n, k)
- {
- register LINE *dlp;
-
- if (n < 0)
- return (backline(f, -n, KRANDOM));
- if ((lastflag&CFCPCN) == 0) /* Fix goal. */
- setgoal();
- thisflag |= CFCPCN;
- dlp = curwp->w_dotp;
- while (n-- && dlp!=curbp->b_linep)
- dlp = lforw(dlp);
- curwp->w_dotp = dlp;
- curwp->w_doto = getgoal(dlp);
- curwp->w_flag |= WFMOVE;
- return (TRUE);
- }
-
- /*
- * This function is like "forwline", but
- * goes backwards. The scheme is exactly the same.
- * Check for arguments that are less than zero and
- * call your alternate. Figure out the new line and
- * call "movedot" to perform the motion.
- */
- backline(f, n, k)
- {
- register LINE *dlp;
-
- if (n < 0)
- return (forwline(f, -n, KRANDOM));
- if ((lastflag&CFCPCN) == 0) /* Fix goal. */
- setgoal();
- thisflag |= CFCPCN;
- dlp = curwp->w_dotp;
- while (n-- && lback(dlp)!=curbp->b_linep)
- dlp = lback(dlp);
- curwp->w_dotp = dlp;
- curwp->w_doto = getgoal(dlp);
- curwp->w_flag |= WFMOVE;
- return (TRUE);
- }
-
- /*
- * Set the current goal column,
- * which is saved in the external variable "curgoal",
- * to the current cursor column. The column is never off
- * the edge of the screen; it's more like display then
- * show position.
- */
- setgoal()
- {
- register int c;
- register int i;
-
- curgoal = 0; /* Get the position. */
- for (i=0; i<curwp->w_doto; ++i) {
- c = lgetc(curwp->w_dotp, i);
- if (c == '\t')
- curgoal |= 0x07;
- else if (ISCTRL(c) != FALSE)
- ++curgoal;
- ++curgoal;
- }
- if (curgoal >= ncol) /* Chop to tty width. */
- curgoal = ncol-1;
- }
-
- /*
- * This routine looks at a line (pointed
- * to by the LINE pointer "dlp") and the current
- * vertical motion goal column (set by the "setgoal"
- * routine above) and returns the best offset to use
- * when a vertical motion is made into the line.
- */
- getgoal(dlp)
- register LINE *dlp;
- {
- register int c;
- register int col;
- register int newcol;
- register int dbo;
-
- col = 0;
- dbo = 0;
- while (dbo != llength(dlp)) {
- c = lgetc(dlp, dbo);
- newcol = col;
- if (c == '\t')
- newcol |= 0x07;
- else if (ISCTRL(c) != FALSE)
- ++newcol;
- ++newcol;
- if (newcol > curgoal)
- break;
- col = newcol;
- ++dbo;
- }
- return (dbo);
- }
-
- /*
- * Scroll forward by a specified number
- * of lines, or by a full page if no argument.
- * The "2" is the window overlap (this is the default
- * value from ITS EMACS). Because the top line in
- * the window is zapped, we have to do a hard
- * update and get it back.
- */
- forwpage(f, n, k)
- register int n;
- {
- register LINE *lp;
-
- if (f == FALSE) {
- n = curwp->w_ntrows - 2; /* Default scroll. */
- if (n <= 0) /* Forget the overlap */
- n = 1; /* if tiny window. */
- } else if (n < 0)
- return (backpage(f, -n, KRANDOM));
- #if CVMVAS
- else /* Convert from pages */
- n *= curwp->w_ntrows; /* to lines. */
- #endif
- lp = curwp->w_linep;
- while (n-- && lp!=curbp->b_linep)
- lp = lforw(lp);
- curwp->w_linep = lp;
- curwp->w_dotp = lp;
- curwp->w_doto = 0;
- curwp->w_flag |= WFHARD;
- return (TRUE);
- }
-
- /*
- * This command is like "forwpage",
- * but it goes backwards. The "2", like above,
- * is the overlap between the two windows. The
- * value is from the ITS EMACS manual. The
- * hard update is done because the top line in
- * the window is zapped.
- */
- backpage(f, n, k)
- register int n;
- {
- register LINE *lp;
-
- if (f == FALSE) {
- n = curwp->w_ntrows - 2; /* Default scroll. */
- if (n <= 0) /* Don't blow up if the */
- n = 1; /* window is tiny. */
- } else if (n < 0)
- return (forwpage(f, -n, KRANDOM));
- #if CVMVAS
- else /* Convert from pages */
- n *= curwp->w_ntrows; /* to lines. */
- #endif
- lp = curwp->w_linep;
- while (n-- && lback(lp)!=curbp->b_linep)
- lp = lback(lp);
- curwp->w_linep = lp;
- curwp->w_dotp = lp;
- curwp->w_doto = 0;
- curwp->w_flag |= WFHARD;
- return (TRUE);
- }
-
- /*
- * Set the mark in the current window
- * to the value of dot. A message is written to
- * the echo line unless we are running in a keyboard
- * macro, when it would be silly.
- */
- setmark(f, n, k)
- {
- curwp->w_markp = curwp->w_dotp;
- curwp->w_marko = curwp->w_doto;
- if (kbdmop == NULL)
- eprintf("[Mark set]");
- return (TRUE);
- }
-
- /*
- * Swap the values of "dot" and "mark" in
- * the current window. This is pretty easy, because
- * all of the hard work gets done by the standard routine
- * that moves the mark about. The only possible
- * error is "no mark".
- */
- swapmark(f, n, k)
- {
- register LINE *odotp;
- register int odoto;
-
- if (curwp->w_markp == NULL) {
- eprintf("No mark in this window");
- return (FALSE);
- }
- odotp = curwp->w_dotp;
- odoto = curwp->w_doto;
- curwp->w_dotp = curwp->w_markp;
- curwp->w_doto = curwp->w_marko;
- curwp->w_markp = odotp;
- curwp->w_marko = odoto;
- curwp->w_flag |= WFMOVE;
- return (TRUE);
- }
-
- /*
- * Go to a specific line, mostly for
- * looking up errors in C programs, which give the
- * error a line number. If an argument is present, then
- * it is the line number, else prompt for a line number
- * to use.
- */
- gotoline(f, n, k)
- register int n;
- {
- register LINE *clp;
- register int s;
- char buf[32];
-
- if (f == FALSE) {
- if ((s=ereply("Goto line: ", buf, sizeof(buf))) != TRUE)
- return (s);
- n = atoi(buf);
- }
- if (n <= 0) {
- eprintf("Bad line");
- return (FALSE);
- }
- clp = lforw(curbp->b_linep); /* "clp" is first line */
- while (n != 1) {
- if (clp == curbp->b_linep) {
- eprintf("Line number too large");
- return (FALSE);
- }
- clp = lforw(clp);
- --n;
- }
- curwp->w_dotp = clp;
- curwp->w_doto = 0;
- curwp->w_flag |= WFMOVE;
- return (TRUE);
- }
- SHAR_EOF
- if test 7726 -ne "`wc -c < 'basic.c'`"
- then
- echo shar: error transmitting "'basic.c'" '(should have been 7726 characters)'
- fi
- fi
- echo shar: extracting "'buffer.c'" '(8922 characters)'
- if test -f 'buffer.c'
- then
- echo shar: will not over-write existing file "'buffer.c'"
- else
- cat << \SHAR_EOF > 'buffer.c'
- /*
- * Name: MicroEMACS
- * Buffer handling.
- * Version: 30
- * Last edit: 17-Feb-86
- * By: rex::conroy
- * decvax!decwrl!dec-rhea!dec-rex!conroy
- */
- #include "def.h"
-
- /*
- * Attach a buffer to a window. The
- * values of dot and mark come from the buffer
- * if the use count is 0. Otherwise, they come
- * from some other window.
- */
- usebuffer(f, n, k)
- {
- register BUFFER *bp;
- register WINDOW *wp;
- register int s;
- char bufn[NBUFN];
-
- if ((s=ereply("Use buffer: ", bufn, NBUFN)) != TRUE)
- return (s);
- if ((bp=bfind(bufn, TRUE)) == NULL)
- return (FALSE);
- if (--curbp->b_nwnd == 0) { /* Last use. */
- curbp->b_dotp = curwp->w_dotp;
- curbp->b_doto = curwp->w_doto;
- curbp->b_markp = curwp->w_markp;
- curbp->b_marko = curwp->w_marko;
- }
- curbp = bp; /* Switch. */
- curwp->w_bufp = bp;
- curwp->w_linep = bp->b_linep; /* For macros, ignored. */
- curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty. */
- if (bp->b_nwnd++ == 0) { /* First use. */
- curwp->w_dotp = bp->b_dotp;
- curwp->w_doto = bp->b_doto;
- curwp->w_markp = bp->b_markp;
- curwp->w_marko = bp->b_marko;
- return (TRUE);
- }
- wp = wheadp; /* Look for old. */
- while (wp != NULL) {
- if (wp!=curwp && wp->w_bufp==bp) {
- curwp->w_dotp = wp->w_dotp;
- curwp->w_doto = wp->w_doto;
- curwp->w_markp = wp->w_markp;
- curwp->w_marko = wp->w_marko;
- break;
- }
- wp = wp->w_wndp;
- }
- return (TRUE);
- }
-
- /*
- * Dispose of a buffer, by name.
- * Ask for the name. Look it up (don't get too
- * upset if it isn't there at all!). Get quite upset
- * if the buffer is being displayed. Clear the buffer (ask
- * if the buffer has been changed). Then free the header
- * line and the buffer header. Bound to "C-X K".
- */
- killbuffer(f, n, k)
- {
- register BUFFER *bp;
- register BUFFER *bp1;
- register BUFFER *bp2;
- register int s;
- char bufn[NBUFN];
-
- if ((s=ereply("Kill buffer: ", bufn, NBUFN)) != TRUE)
- return (s);
- if ((bp=bfind(bufn, FALSE)) == NULL) /* Easy if unknown. */
- return (TRUE);
- if (bp->b_nwnd != 0) { /* Error if on screen. */
- eprintf("Buffer is being displayed");
- return (FALSE);
- }
- if ((s=bclear(bp)) != TRUE) /* Blow text away. */
- return (s);
- free((char *) bp->b_linep); /* Release header line. */
- bp1 = NULL; /* Find the header. */
- bp2 = bheadp;
- while (bp2 != bp) {
- bp1 = bp2;
- bp2 = bp2->b_bufp;
- }
- bp2 = bp2->b_bufp; /* Next one in chain. */
- if (bp1 == NULL) /* Unlink it. */
- bheadp = bp2;
- else
- bp1->b_bufp = bp2;
- free((char *) bp); /* Release buffer block */
- return (TRUE);
- }
-
- /*
- * Display the buffer list. This is done
- * in two parts. The "makelist" routine figures out
- * the text, and puts it in the buffer whoses header is
- * pointed to by the external "blistp". The "popblist"
- * then pops the data onto the screen. Bound to
- * "C-X C-B".
- */
- listbuffers(f, n, k)
- {
- register int s;
-
- if ((s=makelist()) != TRUE)
- return (s);
- return (popblist());
- }
-
- /*
- * Pop the special buffer whose
- * buffer header is pointed to by the external
- * variable "blistp" onto the screen. This is used
- * by the "listbuffers" routine (above) and by
- * some other packages. Returns a status.
- */
- popblist()
- {
- register WINDOW *wp;
- register BUFFER *bp;
-
- if (blistp->b_nwnd == 0) { /* Not on screen yet. */
- if ((wp=wpopup()) == NULL)
- return (FALSE);
- bp = wp->w_bufp;
- if (--bp->b_nwnd == 0) {
- bp->b_dotp = wp->w_dotp;
- bp->b_doto = wp->w_doto;
- bp->b_markp = wp->w_markp;
- bp->b_marko = wp->w_marko;
- }
- wp->w_bufp = blistp;
- ++blistp->b_nwnd;
- }
- wp = wheadp;
- while (wp != NULL) {
- if (wp->w_bufp == blistp) {
- wp->w_linep = lforw(blistp->b_linep);
- wp->w_dotp = lforw(blistp->b_linep);
- wp->w_doto = 0;
- wp->w_markp = NULL;
- wp->w_marko = 0;
- wp->w_flag |= WFMODE|WFHARD;
- }
- wp = wp->w_wndp;
- }
- return (TRUE);
- }
-
- /*
- * This routine rebuilds the
- * text in the special secret buffer
- * that holds the buffer list. It is called
- * by the list buffers command. Return TRUE
- * if everything works. Return FALSE if there
- * is an error (if there is no memory).
- */
- makelist()
- {
- register char *cp1;
- register char *cp2;
- register int c;
- register BUFFER *bp;
- register LINE *lp;
- register int nbytes;
- register int s;
- char b[6+1];
- char line[128];
-
- blistp->b_flag &= ~BFCHG; /* Blow away old. */
- if ((s=bclear(blistp)) != TRUE)
- return (s);
- strcpy(blistp->b_fname, "");
- if (addline("C Size Buffer File") == FALSE
- || addline("- ---- ------ ----") == FALSE)
- return (FALSE);
- bp = bheadp; /* For all buffers */
- while (bp != NULL) {
- cp1 = &line[0]; /* Start at left edge */
- if ((bp->b_flag&BFCHG) != 0) /* "*" if changed */
- *cp1++ = '*';
- else
- *cp1++ = ' ';
- *cp1++ = ' '; /* Gap. */
- nbytes = 0; /* Count bytes in buf. */
- lp = lforw(bp->b_linep);
- while (lp != bp->b_linep) {
- nbytes += llength(lp)+1;
- lp = lforw(lp);
- }
- itoa(b, 6, nbytes); /* 6 digit buffer size. */
- cp2 = &b[0];
- while ((c = *cp2++) != 0)
- *cp1++ = c;
- *cp1++ = ' '; /* Gap. */
- cp2 = &bp->b_bname[0]; /* Buffer name */
- while ((c = *cp2++) != 0)
- *cp1++ = c;
- cp2 = &bp->b_fname[0]; /* File name */
- if (*cp2 != 0) {
- while (cp1 < &line[1+1+6+1+NBUFN+1])
- *cp1++ = ' ';
- while ((c = *cp2++) != 0) {
- if (cp1 < &line[128-1])
- *cp1++ = c;
- }
- }
- *cp1 = 0; /* Add to the buffer. */
- if (addline(line) == FALSE)
- return (FALSE);
- bp = bp->b_bufp;
- }
- return (TRUE); /* All done */
- }
-
- /*
- * Used above.
- */
- itoa(buf, width, num)
- register char buf[];
- register int width;
- register int num;
- {
- buf[width] = 0; /* End of string. */
- while (num >= 10) { /* Conditional digits. */
- buf[--width] = (num%10) + '0';
- num /= 10;
- }
- buf[--width] = num + '0'; /* Always 1 digit. */
- while (width != 0) /* Pad with blanks. */
- buf[--width] = ' ';
- }
-
- /*
- * The argument "text" points to
- * a string. Append this line to the
- * buffer list buffer. Handcraft the EOL
- * on the end. Return TRUE if it worked and
- * FALSE if you ran out of room.
- */
- addline(text)
- char *text;
- {
- register LINE *lp;
- register int i;
- register int ntext;
-
- ntext = strlen(text);
- if ((lp=lalloc(ntext)) == NULL)
- return (FALSE);
- for (i=0; i<ntext; ++i)
- lputc(lp, i, text[i]);
- blistp->b_linep->l_bp->l_fp = lp; /* Hook onto the end */
- lp->l_bp = blistp->b_linep->l_bp;
- blistp->b_linep->l_bp = lp;
- lp->l_fp = blistp->b_linep;
- if (blistp->b_dotp == blistp->b_linep) /* If "." is at the end */
- blistp->b_dotp = lp; /* move it to new line */
- return (TRUE);
- }
-
- /*
- * Look through the list of
- * buffers. Return TRUE if there
- * are any changed buffers. Special buffers
- * like the buffer list buffer don't count, as
- * they are not in the list. Return FALSE if
- * there are no changed buffers.
- */
- anycb()
- {
- register BUFFER *bp;
-
- bp = bheadp;
- while (bp != NULL) {
- if ((bp->b_flag&BFCHG) != 0)
- return (TRUE);
- bp = bp->b_bufp;
- }
- return (FALSE);
- }
-
- /*
- * Search for a buffer, by name.
- * If not found, and the "cflag" is TRUE,
- * create a buffer and put it in the list of
- * all buffers. Return pointer to the BUFFER
- * block for the buffer.
- */
- BUFFER *
- bfind(bname, cflag)
- register char *bname;
- {
- register BUFFER *bp;
-
- bp = bheadp;
- while (bp != NULL) {
- if (strcmp(bname, bp->b_bname) == 0)
- return (bp);
- bp = bp->b_bufp;
- }
- if (cflag!=FALSE && (bp=bcreate(bname))!=NULL) {
- bp->b_bufp = bheadp;
- bheadp = bp;
- }
- return (bp);
- }
-
- /*
- * Create a buffer, by name.
- * Return a pointer to the BUFFER header
- * block, or NULL if the buffer cannot
- * be created. The BUFFER is not put in the
- * list of all buffers; this is called by
- * "edinit" to create the buffer list
- * buffer.
- */
- BUFFER *
- bcreate(bname)
- register char *bname;
- {
- register BUFFER *bp;
- register LINE *lp;
-
- if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL)
- return (NULL);
- if ((lp=lalloc(0)) == NULL) {
- free((char *) bp);
- return (NULL);
- }
- bp->b_bufp = NULL;
- bp->b_dotp = lp;
- bp->b_doto = 0;
- bp->b_markp = NULL;
- bp->b_marko = 0;
- bp->b_flag = 0;
- bp->b_nwnd = 0;
- bp->b_linep = lp;
- strcpy(bp->b_fname, "");
- strcpy(bp->b_bname, bname);
- lp->l_fp = lp;
- lp->l_bp = lp;
- return (bp);
- }
-
- /*
- * This routine blows away all of the text
- * in a buffer. If the buffer is marked as changed
- * then we ask if it is ok to blow it away; this is
- * to save the user the grief of losing text. The
- * window chain is nearly always wrong if this gets
- * called; the caller must arrange for the updates
- * that are required. Return TRUE if everything
- * looks good.
- */
- bclear(bp)
- register BUFFER *bp;
- {
- register LINE *lp;
- register int s;
-
- if ((bp->b_flag&BFCHG) != 0 /* Changed. */
- && (s=eyesno("Discard changes")) != TRUE)
- return (s);
- bp->b_flag &= ~BFCHG; /* Not changed */
- while ((lp=lforw(bp->b_linep)) != bp->b_linep)
- lfree(lp);
- bp->b_dotp = bp->b_linep; /* Fix "." */
- bp->b_doto = 0;
- bp->b_markp = NULL; /* Invalidate "mark" */
- bp->b_marko = 0;
- return (TRUE);
- }
- SHAR_EOF
- if test 8922 -ne "`wc -c < 'buffer.c'`"
- then
- echo shar: error transmitting "'buffer.c'" '(should have been 8922 characters)'
- fi
- fi
- echo shar: extracting "'cinfo.c'" '(2394 characters)'
- if test -f 'cinfo.c'
- then
- echo shar: will not over-write existing file "'cinfo.c'"
- else
- cat << \SHAR_EOF > 'cinfo.c'
- /*
- * Name: MicroEMACS
- * Character class tables.
- * Version: 29
- * Last edit: 05-Feb-86
- * By: rex::conroy
- * decvax!decwrl!dec-rhea!dec-rex!conroy
- *
- * Do it yourself character classification
- * macros, that understand the multinational character set,
- * and let me ask some questions the standard macros (in
- * ctype.h) don't let you ask.
- */
- #include "def.h"
-
- /*
- * This table, indexed by a character drawn
- * from the 256 member character set, is used by my
- * own character type macros to answer questions about the
- * type of a character. It handles the full multinational
- * character set, and lets me ask some questions that the
- * standard "ctype" macros cannot ask.
- */
- char cinfo[256] = {
- _C, _C, _C, _C, /* 0x0X */
- _C, _C, _C, _C,
- _C, _C, _C, _C,
- _C, _C, _C, _C,
- _C, _C, _C, _C, /* 0x1X */
- _C, _C, _C, _C,
- _C, _C, _C, _C,
- _C, _C, _C, _C,
- 0, 0, 0, 0, /* 0x2X */
- _W, 0, 0, _W,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- _W, _W, _W, _W, /* 0x3X */
- _W, _W, _W, _W,
- _W, _W, 0, 0,
- 0, 0, 0, 0,
- 0, _U|_W, _U|_W, _U|_W, /* 0x4X */
- _U|_W, _U|_W, _U|_W, _U|_W,
- _U|_W, _U|_W, _U|_W, _U|_W,
- _U|_W, _U|_W, _U|_W, _U|_W,
- _U|_W, _U|_W, _U|_W, _U|_W, /* 0x5X */
- _U|_W, _U|_W, _U|_W, _U|_W,
- _U|_W, _U|_W, _U|_W, 0,
- 0, 0, 0, _W,
- 0, _L|_W, _L|_W, _L|_W, /* 0x6X */
- _L|_W, _L|_W, _L|_W, _L|_W,
- _L|_W, _L|_W, _L|_W, _L|_W,
- _L|_W, _L|_W, _L|_W, _L|_W,
- _L|_W, _L|_W, _L|_W, _L|_W, /* 0x7X */
- _L|_W, _L|_W, _L|_W, _L|_W,
- _L|_W, _L|_W, _L|_W, 0,
- 0, 0, 0, _C,
- 0, 0, 0, 0, /* 0x8X */
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, /* 0x9X */
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, /* 0xAX */
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, /* 0xBX */
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- _U|_W, _U|_W, _U|_W, _U|_W, /* 0xCX */
- _U|_W, _U|_W, _U|_W, _U|_W,
- _U|_W, _U|_W, _U|_W, _U|_W,
- _U|_W, _U|_W, _U|_W, _U|_W,
- 0, _U|_W, _U|_W, _U|_W, /* 0xDX */
- _U|_W, _U|_W, _U|_W, _U|_W,
- _U|_W, _U|_W, _U|_W, _U|_W,
- _U|_W, _U|_W, 0, _W,
- _L|_W, _L|_W, _L|_W, _L|_W, /* 0xEX */
- _L|_W, _L|_W, _L|_W, _L|_W,
- _L|_W, _L|_W, _L|_W, _L|_W,
- _L|_W, _L|_W, _L|_W, _L|_W,
- 0, _L|_W, _L|_W, _L|_W, /* 0xFX */
- _L|_W, _L|_W, _L|_W, _L|_W,
- _L|_W, _L|_W, _L|_W, _L|_W,
- _L|_W, _L|_W, 0, 0
- };
- SHAR_EOF
- if test 2394 -ne "`wc -c < 'cinfo.c'`"
- then
- echo shar: error transmitting "'cinfo.c'" '(should have been 2394 characters)'
- fi
- fi
- echo shar: extracting "'def.h'" '(10999 characters)'
- if test -f 'def.h'
- then
- echo shar: will not over-write existing file "'def.h'"
- else
- cat << \SHAR_EOF > 'def.h'
- /*
- * Name: MicroEMACS
- * Common header file.
- * Version: 29
- * Last edit: 14-Feb-86
- * By: rex::conroy
- * decvax!decwrl!dec-rhea!dec-rex!conroy
- *
- * This file is the general header file for all parts
- * of the MicroEMACS display editor. It contains all of the
- * general definitions and macros. It also contains some
- * conditional compilation flags. All of the per-system and
- * per-terminal definitions are in special header files.
- * The most common reason to edit this file would be to zap
- * the definition of CVMVAS or BACKUP.
- */
- #include "sysdef.h" /* Order is critical. */
- #include "ttydef.h"
- #include <stdio.h>
-
- #define CVMVAS 1 /* C-V, M-V work in pages. */
- #define BACKUP 0 /* Make backup file. */
-
- /*
- * Table sizes, etc.
- */
- #define NSHASH 31 /* Symbol table hash size. */
- #define NFILEN 80 /* Length, file name. */
- #define NBUFN 16 /* Length, buffer name. */
- #define NLINE 256 /* Length, line. */
- #define NKBDM 256 /* Length, keyboard macro. */
- #define NMSG 512 /* Length, message buffer. */
- #define NPAT 80 /* Length, pattern. */
- #define HUGE 1000 /* A rather large number. */
- #define NSRCH 128 /* Undoable search commands. */
- #define NXNAME 64 /* Length, extended command. */
-
- /*
- * Universal.
- */
- #define FALSE 0 /* False, no, bad, etc. */
- #define TRUE 1 /* True, yes, good, etc. */
- #define ABORT 2 /* Death, ^G, abort, etc. */
-
- /*
- * These flag bits keep track of
- * some aspects of the last command. The CFCPCN
- * flag controls goal column setting. The CFKILL
- * flag controls the clearing versus appending
- * of data in the kill buffer.
- */
- #define CFCPCN 0x0001 /* Last command was C-P, C-N */
- #define CFKILL 0x0002 /* Last command was a kill */
-
- /*
- * File I/O.
- */
- #define FIOSUC 0 /* Success. */
- #define FIOFNF 1 /* File not found. */
- #define FIOEOF 2 /* End of file. */
- #define FIOERR 3 /* Error. */
-
- /*
- * Directory I/O.
- */
- #define DIOSUC 0 /* Success. */
- #define DIOEOF 1 /* End of file. */
- #define DIOERR 2 /* Error. */
-
- /*
- * Display colors.
- */
- #define CNONE 0 /* Unknown color. */
- #define CTEXT 1 /* Text color. */
- #define CMODE 2 /* Mode line color. */
-
- /*
- * Flags for "eread".
- */
- #define EFNEW 0x0001 /* New prompt. */
- #define EFAUTO 0x0002 /* Autocompletion enabled. */
- #define EFCR 0x0004 /* Echo CR at end; last read. */
-
- /*
- * Keys are represented inside using an 11 bit
- * keyboard code. The transformation between the keys on
- * the keyboard and 11 bit code is done by terminal specific
- * code in the "kbd.c" file. The actual character is stored
- * in 8 bits (DEC multinationals work); there is also a control
- * flag KCTRL, a meta flag KMETA, and a control-X flag KCTLX.
- * ASCII control characters are always represented using the
- * KCTRL form. Although the C0 control set is free, it is
- * reserved for C0 controls because it makes the communication
- * between "getkey" and "getkbd" easier. The funny keys get
- * mapped into the C1 control area.
- */
- #define NKEYS 2048 /* 11 bit code. */
-
- #define METACH 0x1B /* M- prefix, Control-[, ESC */
- #define CTMECH 0x1C /* C-M- prefix, Control-\ */
- #define EXITCH 0x1D /* Exit level, Control-] */
- #define CTRLCH 0x1E /* C- prefix, Control-^ */
- #define HELPCH 0x1F /* Help key, Control-_ */
-
- #define KCHAR 0x00FF /* The basic character code. */
- #define KCTRL 0x0100 /* Control flag. */
- #define KMETA 0x0200 /* Meta flag. */
- #define KCTLX 0x0400 /* Control-X flag. */
-
- #define KFIRST 0x0080 /* First special. */
- #define KLAST 0x009F /* Last special. */
-
- #define KRANDOM 0x0080 /* A "no key" code. */
- #define K01 0x0081 /* Use these names to define */
- #define K02 0x0082 /* the special keys on your */
- #define K03 0x0083 /* terminal. */
- #define K04 0x0084
- #define K05 0x0085
- #define K06 0x0086
- #define K07 0x0087
- #define K08 0x0088
- #define K09 0x0089
- #define K0A 0x008A
- #define K0B 0x008B
- #define K0C 0x008C
- #define K0D 0x008D
- #define K0E 0x008E
- #define K0F 0x008F
- #define K10 0x0090
- #define K11 0x0091
- #define K12 0x0092
- #define K13 0x0093
- #define K14 0x0094
- #define K15 0x0095
- #define K16 0x0096
- #define K17 0x0097
- #define K18 0x0098
- #define K19 0x0099
- #define K1A 0x009A
- #define K1B 0x009B
- #define K1C 0x009C
- #define K1D 0x009D
- #define K1E 0x009E
- #define K1F 0x009F
-
- /*
- * These flags, and the macros below them,
- * make up a do-it-yourself set of "ctype" macros that
- * understand the DEC multinational set, and let me ask
- * a slightly different set of questions.
- */
- #define _W 0x01 /* Word. */
- #define _U 0x02 /* Upper case letter. */
- #define _L 0x04 /* Lower case letter. */
- #define _C 0x08 /* Control. */
-
- #define ISWORD(c) ((cinfo[(c)]&_W)!=0)
- #define ISCTRL(c) ((cinfo[(c)]&_C)!=0)
- #define ISUPPER(c) ((cinfo[(c)]&_U)!=0)
- #define ISLOWER(c) ((cinfo[(c)]&_L)!=0)
- #define TOUPPER(c) ((c)-0x20)
- #define TOLOWER(c) ((c)+0x20)
-
- /*
- * The symbol table links editing functions
- * to names. Entries in the key map point at the symbol
- * table entry. A reference count is kept, but it is
- * probably next to useless right now. The old type code,
- * which was not being used and probably not right
- * anyway, is all gone.
- */
- typedef struct SYMBOL {
- struct SYMBOL *s_symp; /* Hash chain. */
- short s_nkey; /* Count of keys bound here. */
- char *s_name; /* Name. */
- int (*s_funcp)(); /* Function. */
- } SYMBOL;
-
- /*
- * There is a window structure allocated for
- * every active display window. The windows are kept in a
- * big list, in top to bottom screen order, with the listhead at
- * "wheadp". Each window contains its own values of dot and mark.
- * The flag field contains some bits that are set by commands
- * to guide redisplay; although this is a bit of a compromise in
- * terms of decoupling, the full blown redisplay is just too
- * expensive to run for every input character.
- */
- typedef struct WINDOW {
- struct WINDOW *w_wndp; /* Next window */
- struct BUFFER *w_bufp; /* Buffer displayed in window */
- struct LINE *w_linep; /* Top line in the window */
- struct LINE *w_dotp; /* Line containing "." */
- short w_doto; /* Byte offset for "." */
- struct LINE *w_markp; /* Line containing "mark" */
- short w_marko; /* Byte offset for "mark" */
- char w_toprow; /* Origin 0 top row of window */
- char w_ntrows; /* # of rows of text in window */
- char w_force; /* If NZ, forcing row. */
- char w_flag; /* Flags. */
- } WINDOW;
-
- /*
- * Window flags are set by command processors to
- * tell the display system what has happened to the buffer
- * mapped by the window. Setting "WFHARD" is always a safe thing
- * to do, but it may do more work than is necessary. Always try
- * to set the simplest action that achieves the required update.
- * Because commands set bits in the "w_flag", update will see
- * all change flags, and do the most general one.
- */
- #define WFFORCE 0x01 /* Force reframe. */
- #define WFMOVE 0x02 /* Movement from line to line. */
- #define WFEDIT 0x04 /* Editing within a line. */
- #define WFHARD 0x08 /* Better to a full display. */
- #define WFMODE 0x10 /* Update mode line. */
-
- /*
- * Text is kept in buffers. A buffer header, described
- * below, exists for every buffer in the system. The buffers are
- * kept in a big list, so that commands that search for a buffer by
- * name can find the buffer header. There is a safe store for the
- * dot and mark in the header, but this is only valid if the buffer
- * is not being displayed (that is, if "b_nwnd" is 0). The text for
- * the buffer is kept in a circularly linked list of lines, with
- * a pointer to the header line in "b_linep".
- */
- typedef struct BUFFER {
- struct BUFFER *b_bufp; /* Link to next BUFFER */
- struct LINE *b_dotp; /* Link to "." LINE structure */
- short b_doto; /* Offset of "." in above LINE */
- struct LINE *b_markp; /* The same as the above two, */
- short b_marko; /* but for the "mark" */
- struct LINE *b_linep; /* Link to the header LINE */
- char b_nwnd; /* Count of windows on buffer */
- char b_flag; /* Flags */
- char b_fname[NFILEN]; /* File name */
- char b_bname[NBUFN]; /* Buffer name */
- } BUFFER;
-
- #define BFCHG 0x01 /* Changed. */
- #define BFBAK 0x02 /* Need to make a backup. */
-
- /*
- * This structure holds the starting position
- * (as a line/offset pair) and the number of characters in a
- * region of a buffer. This makes passing the specification
- * of a region around a little bit easier.
- * There have been some complaints that the short in this
- * structure is wrong; that a long would be more appropriate.
- * I'll awat more comments from the folks with the little
- * machines; I have a VAX, and everything fits.
- */
- typedef struct {
- struct LINE *r_linep; /* Origin LINE address. */
- short r_offset; /* Origin LINE offset. */
- short r_size; /* Length in characters. */
- } REGION;
-
- /*
- * All text is kept in circularly linked
- * lists of "LINE" structures. These begin at the
- * header line (which is the blank line beyond the
- * end of the buffer). This line is pointed to by
- * the "BUFFER". Each line contains a the number of
- * bytes in the line (the "used" size), the size
- * of the text array, and the text. The end of line
- * is not stored as a byte; it's implied. Future
- * additions will include update hints, and a
- * list of marks into the line.
- */
- typedef struct LINE {
- struct LINE *l_fp; /* Link to the next line */
- struct LINE *l_bp; /* Link to the previous line */
- short l_size; /* Allocated size */
- short l_used; /* Used size */
- #if PCC
- char l_text[1]; /* A bunch of characters. */
- #else
- char l_text[]; /* A bunch of characters. */
- #endif
- } LINE;
-
- /*
- * The rationale behind these macros is that you
- * could (with some editing, like changing the type of a line
- * link from a "LINE *" to a "REFLINE", and fixing the commands
- * like file reading that break the rules) change the actual
- * storage representation of lines to use something fancy on
- * machines with small address spaces.
- */
- #define lforw(lp) ((lp)->l_fp)
- #define lback(lp) ((lp)->l_bp)
- #define lgetc(lp, n) ((lp)->l_text[(n)]&0xFF)
- #define lputc(lp, n, c) ((lp)->l_text[(n)]=(c))
- #define llength(lp) ((lp)->l_used)
-
- /*
- * Externals.
- */
- extern int thisflag;
- extern int lastflag;
- extern int curgoal;
- extern int epresf;
- extern int sgarbf;
- extern WINDOW *curwp;
- extern BUFFER *curbp;
- extern WINDOW *wheadp;
- extern BUFFER *bheadp;
- extern BUFFER *blistp;
- extern short kbdm[];
- extern short *kbdmip;
- extern short *kbdmop;
- extern char pat[];
- extern SYMBOL *symbol[];
- extern SYMBOL *binding[];
- extern BUFFER *bfind();
- extern BUFFER *bcreate();
- extern WINDOW *wpopup();
- extern LINE *lalloc();
- extern int nrow;
- extern int ncol;
- extern char *version[];
- extern int ttrow;
- extern int ttcol;
- extern int tceeol;
- extern int tcinsl;
- extern int tcdell;
- extern char cinfo[];
- extern char *keystrings[];
- extern SYMBOL *symlookup();
- extern int nmsg;
- extern int curmsgf;
- extern int newmsgf;
- extern char msg[];
-
- /*
- * Standard I/O.
- */
- extern char *malloc();
- extern char *strcpy();
- extern char *strcat();
- SHAR_EOF
- if test 10999 -ne "`wc -c < 'def.h'`"
- then
- echo shar: error transmitting "'def.h'" '(should have been 10999 characters)'
- fi
- fi
- echo shar: extracting "'display.c'" '(19660 characters)'
- if test -f 'display.c'
- then
- echo shar: will not over-write existing file "'display.c'"
- else
- cat << \SHAR_EOF > 'display.c'
- /*
- * Name: MicroEMACS
- * Gosling style redisplay.
- * Version: 30
- * Last edit: 10-Feb-86
- * By: rex::conroy
- * decvax!decwrl!dec-rhea!dec-rex!conroy
- *
- * The functions in this file handle redisplay. The
- * redisplay system knows almost nothing about the editing
- * process; the editing functions do, however, set some
- * hints to eliminate a lot of the grinding. There is more
- * that can be done; the "vtputc" interface is a real
- * pig. Two conditional compilation flags; the GOSLING
- * flag enables dynamic programming redisplay, using the
- * algorithm published by Jim Gosling in SIGOA. The MEMMAP
- * changes things around for memory mapped video. With
- * both off, the terminal is a VT52.
- */
- #include "def.h"
-
- /*
- * You can change these back to the types
- * implied by the name if you get tight for space. If you
- * make both of them "int" you get better code on the VAX.
- * They do nothing if this is not Gosling redisplay, except
- * for change the size of a structure that isn't used.
- * A bit of a cheat.
- */
- #define XCHAR int
- #define XSHORT int
-
- /*
- * A video structure always holds
- * an array of characters whose length is equal to
- * the longest line possible. Only some of this is
- * used if "ncol" isn't the same as "NCOL".
- */
- typedef struct {
- short v_hash; /* Hash code, for compares. */
- short v_flag; /* Flag word. */
- short v_color; /* Color of the line. */
- XSHORT v_cost; /* Cost of display. */
- char v_text[NCOL]; /* The actual characters. */
- } VIDEO;
-
- #define VFCHG 0x0001 /* Changed. */
- #define VFHBAD 0x0002 /* Hash and cost are bad. */
-
- /*
- * SCORE structures hold the optimal
- * trace trajectory, and the cost of redisplay, when
- * the dynamic programming redisplay code is used.
- * If no fancy redisplay, this isn't used. The trace index
- * fields can be "char", and the score a "short", but
- * this makes the code worse on the VAX.
- */
- typedef struct {
- XCHAR s_itrace; /* "i" index for track back. */
- XCHAR s_jtrace; /* "j" index for trace back. */
- XSHORT s_cost; /* Display cost. */
- } SCORE;
-
- int sgarbf = TRUE; /* TRUE if screen is garbage. */
- int vtrow = 0; /* Virtual cursor row. */
- int vtcol = 0; /* Virtual cursor column. */
- int tthue = CNONE; /* Current color. */
- int ttrow = HUGE; /* Physical cursor row. */
- int ttcol = HUGE; /* Physical cursor column. */
- int tttop = HUGE; /* Top of scroll region. */
- int ttbot = HUGE; /* Bottom of scroll region. */
-
- VIDEO *vscreen[NROW-1]; /* Edge vector, virtual. */
- VIDEO *pscreen[NROW-1]; /* Edge vector, physical. */
- VIDEO video[2*(NROW-1)]; /* Actual screen data. */
- VIDEO blanks; /* Blank line image. */
-
- #if GOSLING
- /*
- * This matrix is written as an array because
- * we do funny things in the "setscores" routine, which
- * is very compute intensive, to make the subscripts go away.
- * It would be "SCORE score[NROW][NROW]" in old speak.
- * Look at "setscores" to understand what is up.
- */
- SCORE score[NROW*NROW];
- #endif
-
- /*
- * Initialize the data structures used
- * by the display code. The edge vectors used
- * to access the screens are set up. The operating
- * system's terminal I/O channel is set up. Fill the
- * "blanks" array with ASCII blanks. The rest is done
- * at compile time. The original window is marked
- * as needing full update, and the physical screen
- * is marked as garbage, so all the right stuff happens
- * on the first call to redisplay.
- */
- vtinit()
- {
- register VIDEO *vp;
- register int i;
-
- ttopen();
- ttinit();
- vp = &video[0];
- for (i=0; i<NROW-1; ++i) {
- vscreen[i] = vp;
- ++vp;
- pscreen[i] = vp;
- ++vp;
- }
- blanks.v_color = CTEXT;
- for (i=0; i<NCOL; ++i)
- blanks.v_text[i] = ' ';
- }
-
- /*
- * Tidy up the virtual display system
- * in anticipation of a return back to the host
- * operating system. Right now all we do is position
- * the cursor to the last line, erase the line, and
- * close the terminal channel.
- */
- vttidy()
- {
- ttcolor(CTEXT);
- ttnowindow(); /* No scroll window. */
- ttmove(nrow-1, 0); /* Echo line. */
- tteeol();
- tttidy();
- ttflush();
- ttclose();
- }
-
- /*
- * Move the virtual cursor to an origin
- * 0 spot on the virtual display screen. I could
- * store the column as a character pointer to the spot
- * on the line, which would make "vtputc" a little bit
- * more efficient. No checking for errors.
- */
- vtmove(row, col)
- {
- vtrow = row;
- vtcol = col;
- }
-
- /*
- * Write a character to the virtual display,
- * dealing with long lines and the display of unprintable
- * things like control characters. Also expand tabs every 8
- * columns. This code only puts printing characters into
- * the virtual display image. Special care must be taken when
- * expanding tabs. On a screen whose width is not a multiple
- * of 8, it is possible for the virtual cursor to hit the
- * right margin before the next tab stop is reached. This
- * makes the tab code loop if you are not careful.
- * Three guesses how we found this.
- */
- vtputc(c)
- register int c;
- {
- register VIDEO *vp;
-
- vp = vscreen[vtrow];
- if (vtcol >= ncol)
- vp->v_text[ncol-1] = '$';
- else if (c == '\t') {
- do {
- vtputc(' ');
- } while (vtcol<ncol && (vtcol&0x07)!=0);
- } else if (ISCTRL(c) != FALSE) {
- vtputc('^');
- vtputc(c ^ 0x40);
- } else
- vp->v_text[vtcol++] = c;
- }
-
- /*
- * Erase from the end of the
- * software cursor to the end of the
- * line on which the software cursor is
- * located. The display routines will decide
- * if a hardware erase to end of line command
- * should be used to display this.
- */
- vteeol()
- {
- register VIDEO *vp;
-
- vp = vscreen[vtrow];
- while (vtcol < ncol)
- vp->v_text[vtcol++] = ' ';
- }
-
- /*
- * Make sure that the display is
- * right. This is a three part process. First,
- * scan through all of the windows looking for dirty
- * ones. Check the framing, and refresh the screen.
- * Second, make sure that "currow" and "curcol" are
- * correct for the current window. Third, make the
- * virtual and physical screens the same.
- */
- update()
- {
- register LINE *lp;
- register WINDOW *wp;
- register VIDEO *vp1;
- register VIDEO *vp2;
- register int i;
- register int j;
- register int c;
- register int hflag;
- register int currow;
- register int curcol;
- register int offs;
- register int size;
-
- if (curmsgf!=FALSE || newmsgf!=FALSE) {
- wp = wheadp;
- while (wp != NULL) {
- wp->w_flag |= WFMODE; /* Must do mode lines. */
- wp = wp->w_wndp;
- }
- }
- curmsgf = newmsgf; /* Sync. up right now. */
- hflag = FALSE; /* Not hard. */
- wp = wheadp;
- while (wp != NULL) {
- if (wp->w_flag != 0) { /* Need update. */
- if ((wp->w_flag&WFFORCE) == 0) {
- lp = wp->w_linep;
- for (i=0; i<wp->w_ntrows; ++i) {
- if (lp == wp->w_dotp)
- goto out;
- if (lp == wp->w_bufp->b_linep)
- break;
- lp = lforw(lp);
- }
- }
- i = wp->w_force; /* Reframe this one. */
- if (i > 0) {
- --i;
- if (i >= wp->w_ntrows)
- i = wp->w_ntrows-1;
- } else if (i < 0) {
- i += wp->w_ntrows;
- if (i < 0)
- i = 0;
- } else
- i = wp->w_ntrows/2;
- lp = wp->w_dotp;
- while (i!=0 && lback(lp)!=wp->w_bufp->b_linep) {
- --i;
- lp = lback(lp);
- }
- wp->w_linep = lp;
- wp->w_flag |= WFHARD; /* Force full. */
- out:
- lp = wp->w_linep; /* Try reduced update. */
- i = wp->w_toprow;
- if ((wp->w_flag&~WFMODE) == WFEDIT) {
- while (lp != wp->w_dotp) {
- ++i;
- lp = lforw(lp);
- }
- vscreen[i]->v_color = CTEXT;
- vscreen[i]->v_flag |= (VFCHG|VFHBAD);
- vtmove(i, 0);
- for (j=0; j<llength(lp); ++j)
- vtputc(lgetc(lp, j));
- vteeol();
- } else if ((wp->w_flag&(WFEDIT|WFHARD)) != 0) {
- hflag = TRUE;
- while (i < wp->w_toprow+wp->w_ntrows) {
- vscreen[i]->v_color = CTEXT;
- vscreen[i]->v_flag |= (VFCHG|VFHBAD);
- vtmove(i, 0);
- if (lp != wp->w_bufp->b_linep) {
- for (j=0; j<llength(lp); ++j)
- vtputc(lgetc(lp, j));
- lp = lforw(lp);
- }
- vteeol();
- ++i;
- }
- }
- if ((wp->w_flag&WFMODE) != 0)
- modeline(wp);
- wp->w_flag = 0;
- wp->w_force = 0;
- }
- wp = wp->w_wndp;
- }
- lp = curwp->w_linep; /* Cursor location. */
- currow = curwp->w_toprow;
- while (lp != curwp->w_dotp) {
- ++currow;
- lp = lforw(lp);
- }
- curcol = 0;
- i = 0;
- while (i < curwp->w_doto) {
- c = lgetc(lp, i++);
- if (c == '\t')
- curcol |= 0x07;
- else if (ISCTRL(c) != FALSE)
- ++curcol;
- ++curcol;
- }
- if (curcol >= ncol) /* Long line. */
- curcol = ncol-1;
- if (sgarbf != FALSE) { /* Screen is garbage. */
- sgarbf = FALSE; /* Erase-page clears */
- epresf = FALSE; /* the message area. */
- tttop = HUGE; /* Forget where you set */
- ttbot = HUGE; /* scroll region. */
- tthue = CNONE; /* Color unknown. */
- ttmove(0, 0);
- tteeop();
- for (i=0; i<nrow-1; ++i) {
- uline(i, vscreen[i], &blanks);
- ucopy(vscreen[i], pscreen[i]);
- }
- ttmove(currow, curcol);
- ttflush();
- return;
- }
- #if GOSLING
- if (hflag != FALSE) { /* Hard update? */
- for (i=0; i<nrow-1; ++i) { /* Compute hash data. */
- hash(vscreen[i]);
- hash(pscreen[i]);
- }
- offs = 0; /* Get top match. */
- while (offs != nrow-1) {
- vp1 = vscreen[offs];
- vp2 = pscreen[offs];
- if (vp1->v_color != vp2->v_color
- || vp1->v_hash != vp2->v_hash)
- break;
- uline(offs, vp1, vp2);
- ucopy(vp1, vp2);
- ++offs;
- }
- if (offs == nrow-1) { /* Might get it all. */
- ttmove(currow, curcol);
- ttflush();
- return;
- }
- size = nrow-1; /* Get bottom match. */
- while (size != offs) {
- vp1 = vscreen[size-1];
- vp2 = pscreen[size-1];
- if (vp1->v_color != vp2->v_color
- || vp1->v_hash != vp2->v_hash)
- break;
- uline(size-1, vp1, vp2);
- ucopy(vp1, vp2);
- --size;
- }
- if ((size -= offs) == 0) /* Get screen size. */
- abort();
- setscores(offs, size); /* Do hard update. */
- traceback(offs, size, size, size);
- for (i=0; i<size; ++i)
- ucopy(vscreen[offs+i], pscreen[offs+i]);
- ttmove(currow, curcol);
- ttflush();
- return;
- }
- #endif
- for (i=0; i<nrow-1; ++i) { /* Easy update. */
- vp1 = vscreen[i];
- vp2 = pscreen[i];
- if ((vp1->v_flag&VFCHG) != 0) {
- uline(i, vp1, vp2);
- ucopy(vp1, vp2);
- }
- }
- ttmove(currow, curcol);
- ttflush();
- }
-
- /*
- * Update a saved copy of a line,
- * kept in a VIDEO structure. The "vvp" is
- * the one in the "vscreen". The "pvp" is the one
- * in the "pscreen". This is called to make the
- * virtual and physical screens the same when
- * display has done an update.
- */
- ucopy(vvp, pvp)
- register VIDEO *vvp;
- register VIDEO *pvp;
- {
- register int i;
-
- vvp->v_flag &= ~VFCHG; /* Changes done. */
- pvp->v_flag = vvp->v_flag; /* Update model. */
- pvp->v_hash = vvp->v_hash;
- pvp->v_cost = vvp->v_cost;
- pvp->v_color = vvp->v_color;
- for (i=0; i<ncol; ++i)
- pvp->v_text[i] = vvp->v_text[i];
- }
-
- /*
- * Update a single line. This routine only
- * uses basic functionality (no insert and delete character,
- * but erase to end of line). The "vvp" points at the VIDEO
- * structure for the line on the virtual screen, and the "pvp"
- * is the same for the physical screen. Avoid erase to end of
- * line when updating CMODE color lines, because of the way that
- * reverse video works on most terminals.
- */
- uline(row, vvp, pvp)
- VIDEO *vvp;
- VIDEO *pvp;
- {
- #if MEMMAP
- putline(row+1, 1, &vvp->v_text[0]);
- #else
- register char *cp1;
- register char *cp2;
- register char *cp3;
- register char *cp4;
- register char *cp5;
- register int nbflag;
-
- if (vvp->v_color != pvp->v_color) { /* Wrong color, do a */
- ttmove(row, 0); /* full redraw. */
- ttcolor(vvp->v_color);
- cp1 = &vvp->v_text[0];
- cp2 = &vvp->v_text[ncol];
- while (cp1 != cp2) {
- ttputc(*cp1++);
- ++ttcol;
- }
- return;
- }
- cp1 = &vvp->v_text[0]; /* Compute left match. */
- cp2 = &pvp->v_text[0];
- while (cp1!=&vvp->v_text[ncol] && cp1[0]==cp2[0]) {
- ++cp1;
- ++cp2;
- }
- if (cp1 == &vvp->v_text[ncol]) /* All equal. */
- return;
- nbflag = FALSE;
- cp3 = &vvp->v_text[ncol]; /* Compute right match. */
- cp4 = &pvp->v_text[ncol];
- while (cp3[-1] == cp4[-1]) {
- --cp3;
- --cp4;
- if (cp3[0] != ' ') /* Note non-blanks in */
- nbflag = TRUE; /* the right match. */
- }
- cp5 = cp3; /* Is erase good? */
- if (nbflag==FALSE && vvp->v_color==CTEXT) {
- while (cp5!=cp1 && cp5[-1]==' ')
- --cp5;
- /* Alcyon hack */
- if ((int)(cp3-cp5) <= tceeol)
- cp5 = cp3;
- }
- /* Alcyon hack */
- ttmove(row, (int)(cp1-&vvp->v_text[0]));
- ttcolor(vvp->v_color);
- while (cp1 != cp5) {
- ttputc(*cp1++);
- ++ttcol;
- }
- if (cp5 != cp3) /* Do erase. */
- tteeol();
- #endif
- }
-
- /*
- * Redisplay the mode line for
- * the window pointed to by the "wp".
- * This is the only routine that has any idea
- * of how the modeline is formatted. You can
- * change the modeline format by hacking at
- * this routine. Called by "update" any time
- * there is a dirty window.
- */
- modeline(wp)
- register WINDOW *wp;
- {
- register char *cp;
- register int c;
- register int n;
- register BUFFER *bp;
-
- n = wp->w_toprow+wp->w_ntrows; /* Location. */
- vscreen[n]->v_color = CMODE; /* Mode line color. */
- vscreen[n]->v_flag |= (VFCHG|VFHBAD); /* Recompute, display. */
- vtmove(n, 0); /* Seek to right line. */
- bp = wp->w_bufp;
- if ((bp->b_flag&BFCHG) != 0) /* "*" if changed. */
- vtputc('*');
- else
- vtputc(' ');
- n = 1;
- cp = "MicroEMACS"; /* Buffer name. */
- while ((c = *cp++) != 0) {
- vtputc(c);
- ++n;
- }
- if (bp->b_bname[0] != 0) {
- vtputc(' ');
- ++n;
- cp = &bp->b_bname[0];
- while ((c = *cp++) != 0) {
- vtputc(c);
- ++n;
- }
- }
- if (bp->b_fname[0] != 0) { /* File name. */
- vtputc(' ');
- ++n;
- cp = "File:";
- while ((c = *cp++) != 0) {
- vtputc(c);
- ++n;
- }
- cp = &bp->b_fname[0];
- while ((c = *cp++) != 0) {
- vtputc(c);
- ++n;
- }
- }
- if (curmsgf != FALSE /* Message alert. */
- && wp->w_wndp == NULL) {
- while (n < ncol-5-1) {
- vtputc(' ');
- ++n;
- }
- cp = "[Msg]"; /* Sizeof("[Msg]") = 5. */
- while ((c = *cp++) != 0) {
- vtputc(c);
- ++n;
- }
- }
- while (n < ncol) { /* Pad out. */
- vtputc(' ');
- ++n;
- }
- }
-
- #if GOSLING
- /*
- * Compute the hash code for
- * the line pointed to by the "vp". Recompute
- * it if necessary. Also set the approximate redisplay
- * cost. The validity of the hash code is marked by
- * a flag bit. The cost understand the advantages
- * of erase to end of line. Tuned for the VAX
- * by Bob McNamara; better than it used to be on
- * just about any machine.
- */
- hash(vp)
- register VIDEO *vp;
- {
- register int i;
- register int n;
- register char *s;
-
- if ((vp->v_flag&VFHBAD) != 0) { /* Hash bad. */
- s = &vp->v_text[ncol-1];
- for (i=ncol; i!=0; --i, --s)
- if (*s != ' ')
- break;
- n = ncol-i; /* Erase cheaper? */
- if (n > tceeol)
- n = tceeol;
- vp->v_cost = i+n; /* Bytes + blanks. */
- for (n=0; i!=0; --i, --s)
- n = (n<<5) + n + *s;
- vp->v_hash = n; /* Hash code. */
- vp->v_flag &= ~VFHBAD; /* Flag as all done. */
- }
- }
-
- /*
- * Compute the Insert-Delete
- * cost matrix. The dynamic programming algorithm
- * described by James Gosling is used. This code assumes
- * that the line above the echo line is the last line involved
- * in the scroll region. This is easy to arrange on the VT100
- * because of the scrolling region. The "offs" is the origin 0
- * offset of the first row in the virtual/physical screen that
- * is being updated; the "size" is the length of the chunk of
- * screen being updated. For a full screen update, use offs=0
- * and size=nrow-1.
- *
- * Older versions of this code implemented the score matrix by
- * a two dimensional array of SCORE nodes. This put all kinds of
- * multiply instructions in the code! This version is written to
- * use a linear array and pointers, and contains no multiplication
- * at all. The code has been carefully looked at on the VAX, with
- * only marginal checking on other machines for efficiency. In
- * fact, this has been tuned twice! Bob McNamara tuned it even
- * more for the VAX, which is a big issue for him because of
- * the 66 line X displays.
- *
- * On some machines, replacing the "for (i=1; i<=size; ++i)" with
- * i = 1; do { } while (++i <=size)" will make the code quite a
- * bit better; but it looks ugly.
- */
- setscores(offs, size)
- {
- register SCORE *sp;
- register int tempcost;
- register int bestcost;
- register int j;
- register int i;
- register VIDEO **vp;
- register VIDEO **pp;
- register SCORE *sp1;
- register VIDEO **vbase;
- register VIDEO **pbase;
-
- vbase = &vscreen[offs-1]; /* By hand CSE's. */
- pbase = &pscreen[offs-1];
- score[0].s_itrace = 0; /* [0, 0] */
- score[0].s_jtrace = 0;
- score[0].s_cost = 0;
- sp = &score[1]; /* Row 0, inserts. */
- tempcost = 0;
- vp = &vbase[1];
- for (j=1; j<=size; ++j) {
- sp->s_itrace = 0;
- sp->s_jtrace = j-1;
- tempcost += tcinsl;
- tempcost += (*vp)->v_cost;
- sp->s_cost = tempcost;
- ++vp;
- ++sp;
- }
- sp = &score[NROW]; /* Column 0, deletes. */
- tempcost = 0;
- for (i=1; i<=size; ++i) {
- sp->s_itrace = i-1;
- sp->s_jtrace = 0;
- tempcost += tcdell;
- sp->s_cost = tempcost;
- sp += NROW;
- }
- sp1 = &score[NROW+1]; /* [1, 1]. */
- pp = &pbase[1];
- for (i=1; i<=size; ++i) {
- sp = sp1;
- vp = &vbase[1];
- for (j=1; j<=size; ++j) {
- sp->s_itrace = i-1;
- sp->s_jtrace = j;
- bestcost = (sp-NROW)->s_cost;
- if (j != size) /* Cd(A[i])=0 @ Dis. */
- bestcost += tcdell;
- tempcost = (sp-1)->s_cost;
- tempcost += (*vp)->v_cost;
- if (i != size) /* Ci(B[j])=0 @ Dsj. */
- tempcost += tcinsl;
- if (tempcost < bestcost) {
- sp->s_itrace = i;
- sp->s_jtrace = j-1;
- bestcost = tempcost;
- }
- tempcost = (sp-NROW-1)->s_cost;
- if ((*pp)->v_color != (*vp)->v_color
- || (*pp)->v_hash != (*vp)->v_hash)
- tempcost += (*vp)->v_cost;
- if (tempcost < bestcost) {
- sp->s_itrace = i-1;
- sp->s_jtrace = j-1;
- bestcost = tempcost;
- }
- sp->s_cost = bestcost;
- ++sp; /* Next column. */
- ++vp;
- }
- ++pp;
- sp1 += NROW; /* Next row. */
- }
- }
-
- /*
- * Trace back through the dynamic programming cost
- * matrix, and update the screen using an optimal sequence
- * of redraws, insert lines, and delete lines. The "offs" is
- * the origin 0 offset of the chunk of the screen we are about to
- * update. The "i" and "j" are always started in the lower right
- * corner of the matrix, and imply the size of the screen.
- * A full screen traceback is called with offs=0 and i=j=nrow-1.
- * There is some do-it-yourself double subscripting here,
- * which is acceptable because this routine is much less compute
- * intensive then the code that builds the score matrix!
- */
- traceback(offs, size, i, j)
- {
- register int itrace;
- register int jtrace;
- register int k;
- register int ninsl;
- register int ndraw;
- register int ndell;
-
- if (i==0 && j==0) /* End of update. */
- return;
- itrace = score[(NROW*i) + j].s_itrace;
- jtrace = score[(NROW*i) + j].s_jtrace;
- if (itrace == i) { /* [i, j-1] */
- ninsl = 0; /* Collect inserts. */
- if (i != size)
- ninsl = 1;
- ndraw = 1;
- while (itrace!=0 || jtrace!=0) {
- if (score[(NROW*itrace) + jtrace].s_itrace != itrace)
- break;
- jtrace = score[(NROW*itrace) + jtrace].s_jtrace;
- if (i != size)
- ++ninsl;
- ++ndraw;
- }
- traceback(offs, size, itrace, jtrace);
- if (ninsl != 0) {
- ttcolor(CTEXT);
- ttinsl(offs+j-ninsl, offs+size-1, ninsl);
- }
- do { /* B[j], A[j] blank. */
- k = offs+j-ndraw;
- uline(k, vscreen[k], &blanks);
- } while (--ndraw);
- return;
- }
- if (jtrace == j) { /* [i-1, j] */
- ndell = 0; /* Collect deletes. */
- if (j != size)
- ndell = 1;
- while (itrace!=0 || jtrace!=0) {
- if (score[(NROW*itrace) + jtrace].s_jtrace != jtrace)
- break;
- itrace = score[(NROW*itrace) + jtrace].s_itrace;
- if (j != size)
- ++ndell;
- }
- if (ndell != 0) {
- ttcolor(CTEXT);
- ttdell(offs+i-ndell, offs+size-1, ndell);
- }
- traceback(offs, size, itrace, jtrace);
- return;
- }
- traceback(offs, size, itrace, jtrace);
- k = offs+j-1;
- uline(k, vscreen[k], pscreen[offs+i-1]);
- }
- #endif
- SHAR_EOF
- if test 19660 -ne "`wc -c < 'display.c'`"
- then
- echo shar: error transmitting "'display.c'" '(should have been 19660 characters)'
- fi
- fi
- exit 0
- # End of shell archive
-